package com.zfei.gfb.util;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomUtils;

import java.util.*;
import java.util.regex.Pattern;

/**
 * @author fgh
 */
public class Utils {

    /**
     * 将一个list均分成n个list
     *
     * @param source 列表
     * @param n      均分数
     * @param <T>    元素类型
     * @return 均分列表
     */
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {
        List<List<T>> result = new ArrayList<>();
        int remainder = source.size() % n; // 余数
        int number = source.size() / n; // 商
        int offset = 0; // 偏移量
        for (int i = 0; i < n; i++) {
            List<T> value;
            if (remainder > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remainder--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }

    /**
     * 字符串替换
     *
     * @param pattern     正则表达式模型
     * @param source      原始字符串
     * @param replacement 替换字符串
     * @return 替换后的字符串
     */
    public static String replaceAll(Pattern pattern, String source, String replacement) {
        return source != null ? pattern.matcher(source).replaceAll(replacement) : null;
    }

    /**
     * 权重列表随机
     * <p>
     * 示例1：输入列表为[60, 30, 10]，则返回0/1/2的概率分别为60%/30%/10%
     * 示例2：输入列表为[0, 10, 10]，则返回0/1/2的概率分别为0%/50%/50%
     *
     * @param weightList 命中权重列表，列表中各项的累加值没有限制，不一定非要等于100
     * @return 按指定权重所映射的概率，返回命中的下标值
     */
    public static int selectIndex(List<Integer> weightList) {
        List<Integer> weightSumList = new ArrayList<>();
        int maxWeightSum = 0;
        for (int weight : weightList) {
            maxWeightSum += weight;
            weightSumList.add(maxWeightSum);
        }

        int k = RandomUtils.nextInt(0, maxWeightSum);
        for (int i = 0; i < weightSumList.size(); i++) {
            int start = i > 0 ? weightSumList.get(i - 1) : 0;
            int stop = weightSumList.get(i);
            if (k >= start && k < stop) {
                return i;
            }
        }

        return 0;
    }



    /**
     * 生成签名信息
     *
     * @param secretKey 产品私钥
     * @param params    接口请求参数名和参数值map，不包括signature参数名
     * @return 签名
     */
    public static String genSignature(String secretKey, Map<String, Object> params) {
        if (secretKey == null || params == null || params.size() == 0) {
            return "";
        }
        // 1. 参数名按照ASCII码表升序排序
        String[] keys = params.keySet().toArray(new String[0]);
        Arrays.sort(keys);
        // 2. 按照排序拼接参数名与参数值
        StringBuilder paramBuffer = new StringBuilder();
        for (String key : keys) {
            paramBuffer.append(key).append(params.get(key) == null ? "" : params.get(key));
        }
        // 3. 将secretKey拼接到最后
        paramBuffer.append(secretKey);
        // 4. MD5是128位长度的摘要算法，用16进制表示，一个十六进制的字符能表示4个位，所以签名后的字符串长度固定为32个十六进制字符。
        return DigestUtils.md5Hex(paramBuffer.toString());
    }


    private static Random r;

    /**
     * 获取随机子列表
     *
     * @param source 原列表
     * @param limit  子列表长度
     * @param <T>    列表原类型
     * @return 子列表
     */
    public static <T> List<T> newRandomList(List<T> source, int limit) {
        if (source == null || source.size() == 0 || source.size() <= limit) {
            return source;
        }

        Set<Integer> set = createRandomSet(source.size(), limit);
        Integer[] array = set.toArray(new Integer[0]);
        return new RandomList<>(source, array);
    }

    /**
     * 创建一个随机的有序下标Set
     *
     * @param listSize 原列表长度
     * @param limit    子列表长度
     * @return 随机的下标Set
     */
    private static Set<Integer> createRandomSet(int listSize, int limit) {
        Random rnd = r;
        if (rnd == null)
            r = rnd = new Random();

        Set<Integer> set = new HashSet<>(limit);
        for (int i = 0; i < limit; i++) {
            int value = rnd.nextInt(listSize);
            if (!add(set, value, listSize)) {
                return set;
            }
        }
        return set;
    }

    /**
     * 往Set中添加一个随机值，如果有冲突，则取随机值+1
     */
    private static boolean add(Set<Integer> set, int value, int size) {
        if (set.size() == size) {
            return false;
        }

        if (!set.contains(value)) {
            return set.add(value);
        }

        int nextValue = value + 1;
        if (nextValue == size) {
            nextValue = 0;
        }
        return add(set, nextValue, size);
    }


    private static class RandomList<T> extends AbstractList<T> {
        final List<T> list;
        final Integer[] indexs;

        RandomList(List<T> list, Integer[] indexs) {
            this.list = list;
            this.indexs = indexs;
        }

        @Override
        public T get(int index) {
            if (index < 0 || index >= indexs.length)
                throw new IndexOutOfBoundsException("The start index was out of bounds: "
                        + index + " >= " + indexs.length);
            int start = indexs[index];
            return list.get(start);
        }

        @Override
        public int size() {
            return indexs.length;
        }

        @Override
        public boolean isEmpty() {
            return list.isEmpty();
        }
    }


    public static String id() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }



}
